﻿/*----------------------------------------------------------------------------------------
*
*  Copyright 2019, Gao Hai Hui, <fromzeropoint@126.com>.  All rights reserved.
*  https://gitee.com/helloworldghh/xoskit.git
*  Use of this source code is governed by a MIT license
*  that can be found in the License file.
*
----------------------------------------------------------------------------------------*/
#include "../import/head.h"
#include "../global/head.h"
#include "../macro/head.h"
#include "odbc_stmt.h"

namespace xos_odbc
{
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    static odbc_stmt::POOL * pool_ptr = 0;

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    odbc_stmt::odbc_stmt()
    {
        init_data();
    }

    odbc_stmt::~odbc_stmt()
    {
        term();
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //  public method

    int odbc_stmt::get_addr( POOL *** pppPool, LIST *** pppList )
    {
        int ret = 0;
        if( pppPool )
        {
            *pppPool = &pool_ptr;
        }
        if( pppList )
        {
            *pppList = 0;
        }
        return ret;
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // i_odbc_node method

    // 
    // 得到最近的错误信息
    // 
    int odbc_stmt::get_last_err_info( char * lpszInfo, int nSize, int * lpnInfoLen, int * lpnLenNeeded )
    {
        int ret = 0;

        if( 0 == ret )
        {
            m_err.get_info( lpszInfo, nSize, lpnInfoLen, lpnLenNeeded );
        }

        return ret;
    }

    // 
    // 绑定输入参数
    // 
    int odbc_stmt::bind_param( int nCol, enumDirection eType, enumValueType eValueType, 
        enumValueType eParamType, int ColSize,
        int DecimalDigits,
        void * ParamValuePtr,
        int BufLen,
        xos::xos_int * StrLen_or_IndPtr )
    {
        int ret = 0;

        SQLLEN * lpLenOrPtr = ( SQLLEN * )StrLen_or_IndPtr;
        int ValueType = eValueType;
        int ParamType = eParamType;
        int nType = eType;

        if( ( 0 == ret ) && ( SQL_NULL_HSTMT == m_hStmt ) )
        {
            ret = 1;
        }

        if( 0 == ret )
        {
            to_len_or_ptr( *lpLenOrPtr, lpLenOrPtr );
            to_sql_io_type( nType, &nType );
            to_c_type( ValueType, &ValueType );
            to_c_type( ParamType, &ParamType );
        }

        if( 0 == ret )
        {
            SQLRETURN r = SQLBindParameter( m_hStmt, nCol + 1, nType, ValueType, ParamType, ColSize, DecimalDigits, ParamValuePtr, BufLen, lpLenOrPtr );
            ret = m_err.stmt_ret( m_hStmt, r );
        }

        return ret;
    }

    // 
    // 绑定输入参数
    // 
    int odbc_stmt::bind_param( int nCol, const char * lpszData, int nNoop, xos::xos_int * StrLen_or_IndPtr )
    {
        int ret = 0;

        nNoop = 0;

        SQLLEN * lpLenOrPtr = ( SQLLEN * )StrLen_or_IndPtr;
        *lpLenOrPtr = SQL_NTS;
        int ColSize = g_pSysData->m_pContainer->crt()->strlen( lpszData );
        int BufLen = ColSize + 1;
        int DecimalDigits = 0;
        void * ParamValuePtr = ( void * )lpszData;

        if( 0 == ret )
        {
            ret = bind_param( nCol, DIRECT_INPUT, VT_CHAR_ARRAY, VT_CHAR_ARRAY, ColSize, DecimalDigits, ParamValuePtr, BufLen, StrLen_or_IndPtr );
        }

        return ret;
    }

    // 
    // 绑定输入参数
    // 
    int odbc_stmt::bind_param( int nCol, xos::xos_i64 * lpnData, xos::xos_int * StrLen_or_IndPtr )
    {
        int ret = 0;

        SQLLEN * lpLenOrPtr = ( SQLLEN * )StrLen_or_IndPtr;
        *lpLenOrPtr = sizeof( xos::xos_i64 );
        int ColSize = sizeof( xos::xos_i64 );
        int BufLen = ColSize;
        int DecimalDigits = 0;
        void * ParamValuePtr = ( void * )lpnData;

        if( 0 == ret )
        {
            ret = bind_param( nCol, DIRECT_INPUT, VT_I64, VT_I64, ColSize, DecimalDigits, ParamValuePtr, BufLen, StrLen_or_IndPtr );
        }

        return ret;
    }

    // 
    // 绑定输入参数
    // 
    int odbc_stmt::bind_param( int nCol, xos::xos_i32 * lpnData, xos::xos_int * StrLen_or_IndPtr )
    {
        int ret = 0;

        SQLLEN * lpLenOrPtr = ( SQLLEN * )StrLen_or_IndPtr;
        *lpLenOrPtr = sizeof( xos::xos_i32 );
        int ColSize = sizeof( xos::xos_i32 );
        int BufLen = ColSize;
        int DecimalDigits = 0;
        void * ParamValuePtr = ( void * )lpnData;

        if( 0 == ret )
        {
            ret = bind_param( nCol, DIRECT_INPUT, VT_I32, VT_I32, ColSize, DecimalDigits, ParamValuePtr, BufLen, StrLen_or_IndPtr );
        }

        return ret;
    }

    // 
    // 绑定输入参数
    // 
    int odbc_stmt::bind_param( int nCol, xos::xos_i16 * lpnData, xos::xos_int * StrLen_or_IndPtr )
    {
        int ret = 0;

        SQLLEN * lpLenOrPtr = ( SQLLEN * )StrLen_or_IndPtr;
        *lpLenOrPtr = sizeof( xos::xos_i16 );
        int ColSize = sizeof( xos::xos_i16 );
        int BufLen = ColSize;
        int DecimalDigits = 0;
        void * ParamValuePtr = ( void * )lpnData;

        if( 0 == ret )
        {
            ret = bind_param( nCol, DIRECT_INPUT, VT_I16, VT_I16, ColSize, DecimalDigits, ParamValuePtr, BufLen, StrLen_or_IndPtr );
        }

        return ret;
    }

    // 
    // 绑定输入参数
    // 
    int odbc_stmt::bind_param( int nCol, xos::xos_i8 * lpnData, xos::xos_int * StrLen_or_IndPtr )
    {
        int ret = 0;

        SQLLEN * lpLenOrPtr = ( SQLLEN * )StrLen_or_IndPtr;
        *lpLenOrPtr = sizeof( xos::xos_i8 );
        int ColSize = sizeof( xos::xos_i8 );
        int BufLen = ColSize;
        int DecimalDigits = 0;
        void * ParamValuePtr = ( void * )lpnData;

        if( 0 == ret )
        {
            ret = bind_param( nCol, DIRECT_INPUT, VT_I8, VT_I8, ColSize, DecimalDigits, ParamValuePtr, BufLen, StrLen_or_IndPtr );
        }

        return ret;
    }

    // 
    // 绑定输入参数
    // 
    int odbc_stmt::bind_param( int nCol, xos::xos_u64 * lpnData, xos::xos_int * StrLen_or_IndPtr )
    {
        int ret = 0;

        SQLLEN * lpLenOrPtr = ( SQLLEN * )StrLen_or_IndPtr;
        *lpLenOrPtr = sizeof( xos::xos_u64 );
        int ColSize = sizeof( xos::xos_u64 );
        int BufLen = ColSize;
        int DecimalDigits = 0;
        void * ParamValuePtr = ( void * )lpnData;

        if( 0 == ret )
        {
            ret = bind_param( nCol, DIRECT_INPUT, VT_U64, VT_U64, ColSize, DecimalDigits, ParamValuePtr, BufLen, StrLen_or_IndPtr );
        }

        return ret;
    }

    // 
    // 绑定输入参数
    // 
    int odbc_stmt::bind_param( int nCol, xos::xos_u32 * lpnData, xos::xos_int * StrLen_or_IndPtr )
    {
        int ret = 0;

        SQLLEN * lpLenOrPtr = ( SQLLEN * )StrLen_or_IndPtr;
        *lpLenOrPtr = sizeof( xos::xos_u32 );
        int ColSize = sizeof( xos::xos_u32 );
        int BufLen = ColSize;
        int DecimalDigits = 0;
        void * ParamValuePtr = ( void * )lpnData;

        if( 0 == ret )
        {
            ret = bind_param( nCol, DIRECT_INPUT, VT_U32, VT_U32, ColSize, DecimalDigits, ParamValuePtr, BufLen, StrLen_or_IndPtr );
        }

        return ret;
    }

    // 
    // 绑定输入参数
    // 
    int odbc_stmt::bind_param( int nCol, xos::xos_u16 * lpnData, xos::xos_int * StrLen_or_IndPtr )
    {
        int ret = 0;

        SQLLEN * lpLenOrPtr = ( SQLLEN * )StrLen_or_IndPtr;
        *lpLenOrPtr = sizeof( xos::xos_u16 );
        int ColSize = sizeof( xos::xos_u16 );
        int BufLen = ColSize;
        int DecimalDigits = 0;
        void * ParamValuePtr = ( void * )lpnData;

        if( 0 == ret )
        {
            ret = bind_param( nCol, DIRECT_INPUT, VT_U16, VT_U16, ColSize, DecimalDigits, ParamValuePtr, BufLen, StrLen_or_IndPtr );
        }

        return ret;
    }

    // 
    // 绑定输入参数
    // 
    int odbc_stmt::bind_param( int nCol, xos::xos_u8 * lpnData, xos::xos_int * StrLen_or_IndPtr )
    {
        int ret = 0;

        SQLLEN * lpLenOrPtr = ( SQLLEN * )StrLen_or_IndPtr;
        *lpLenOrPtr = sizeof( xos::xos_u8 );
        int ColSize = sizeof( xos::xos_u8 );
        int BufLen = ColSize;
        int DecimalDigits = 0;
        void * ParamValuePtr = ( void * )lpnData;

        if( 0 == ret )
        {
            ret = bind_param( nCol, DIRECT_INPUT, VT_U8, VT_U8, ColSize, DecimalDigits, ParamValuePtr, BufLen, StrLen_or_IndPtr );
        }

        return ret;
    }

    // 
    // 绑定输入参数
    // 
    int odbc_stmt::bind_param( int nCol, bool * lpnData, xos::xos_int * StrLen_or_IndPtr )
    {
        int ret = 0;

        SQLLEN * lpLenOrPtr = ( SQLLEN * )StrLen_or_IndPtr;
        *lpLenOrPtr = sizeof( bool );
        int ColSize = sizeof( bool );
        int BufLen = ColSize;
        int DecimalDigits = 0;
        void * ParamValuePtr = ( void * )lpnData;

        if( 0 == ret )
        {
            ret = bind_param( nCol, DIRECT_INPUT, VT_BOOL, VT_BOOL, ColSize, DecimalDigits, ParamValuePtr, BufLen, StrLen_or_IndPtr );
        }

        return ret;
    }

    // 
    // 绑定输入参数
    // 
    int odbc_stmt::bind_param( int nCol, float * lpfData, int nDigitNum, xos::xos_int * StrLen_or_IndPtr )
    {
        int ret = 0;

        SQLLEN * lpLenOrPtr = ( SQLLEN * )StrLen_or_IndPtr;
        *lpLenOrPtr = sizeof( float );
        int ColSize = sizeof( float );
        int BufLen = ColSize;
        int DecimalDigits = 0;
        void * ParamValuePtr = ( void * )lpfData;

        if( 0 == ret )
        {
            ret = bind_param( nCol, DIRECT_INPUT, VT_FLOAT, VT_FLOAT, ColSize, DecimalDigits, ParamValuePtr, BufLen, StrLen_or_IndPtr );
        }

        return ret;
    }

    // 
    // 绑定输入参数
    // 
    int odbc_stmt::bind_param( int nCol, double * lpdData, int nDigitNum, xos::xos_int * StrLen_or_IndPtr )
    {
        int ret = 0;

        SQLLEN * lpLenOrPtr = ( SQLLEN * )StrLen_or_IndPtr;
        *lpLenOrPtr = sizeof( double );
        int ColSize = sizeof( double );
        int BufLen = ColSize;
        int DecimalDigits = 0;
        void * ParamValuePtr = ( void * )lpdData;

        if( 0 == ret )
        {
            ret = bind_param( nCol, DIRECT_INPUT, VT_DOUBLE, VT_DOUBLE, ColSize, DecimalDigits, ParamValuePtr, BufLen, StrLen_or_IndPtr );
        }

        return ret;
    }

    // 
    // 翻译一下odbc返回的StrLen_or_IndPtr为i_stmt中的enumLenOrPtr类型
    // 
    int odbc_stmt::translate_strlen_or_indptr( xos::xos_int StrLen_or_IndPtr, xos::xos_int * lp_StrLen_or_IndPtr )
    {
        int ret = 0;

        SQLLEN LenOrPtr = ( SQLLEN )StrLen_or_IndPtr;

        if( 0 == ret )
        {
            ret = from_len_or_ptr( LenOrPtr, &LenOrPtr );
        }

        if( ( 0 == ret ) && lp_StrLen_or_IndPtr )
        {
            *lp_StrLen_or_IndPtr = LenOrPtr;
        }

        return ret;
    }

    // 
    // 直接运行sql
    // 
    //  0 : success. 
    //  1 : running. 
    // -1 : failed
    // 
    int odbc_stmt::execute_direct( const char * lpszSql )
    {
        SQLRETURN sqlRet = SQL_SUCCESS;
        int ret = -1;

        if( ( 0 == ret ) && ( SQL_NULL_HSTMT == m_hStmt ) )
        {
            return -1;
        }

        {
            sqlRet = SQLExecDirectA( m_hStmt, ( SQLCHAR * )lpszSql, SQL_NTS );
            ret = m_err.stmt_ret( m_hStmt, sqlRet );
        }

        return ret;
    }

    //
    // 编译sql
    // 
    //  0 : success. 
    //  1 : running. 
    // -1 : failed
    // 
    int odbc_stmt::prepare_sql( const char * lpszSql )
    {
        int ret = 0;

        SQLRETURN sqlRet = SQL_SUCCESS;
        if( lpszSql )
        {
            m_sql = lpszSql;
        }
        {
            sqlRet = SQLPrepareA( m_hStmt, ( SQLCHAR * )m_sql.c_str(), SQL_NTS);
            ret = m_err.stmt_ret( m_hStmt, sqlRet );
        }

        return ret;
    }

    // 
    // 绑定输入后执行sql语句写入
    // 
    //  0 : success. 
    //  1 : running. 
    // -1 : failed
    // 
    int odbc_stmt::execute()
    {
        SQLRETURN sqlRet = SQL_SUCCESS;
        int ret = -1;

        if( ( 0 == ret ) && ( SQL_NULL_HSTMT == m_hStmt ) )
        {
            return -1;
        }

        {
            sqlRet = SQLExecute( m_hStmt );
            ret = m_err.stmt_ret( m_hStmt, sqlRet );
        }

        return ret;
    }

    // 
    // 绑定输出参数
    // 
    int odbc_stmt::bind_colum( int nCol, enumValueType eType, void * pBufByte,
        int nBufSize,
        xos::xos_int * StrLen_or_IndPtr )
    {
        int ret = 0;

        SQLLEN * lpLenOrPtr = ( SQLLEN * )StrLen_or_IndPtr;
        *lpLenOrPtr = 0;
        int nType = eType;

        if( ( 0 == ret ) && ( SQL_NULL_HSTMT == m_hStmt ) )
        {
            ret = 1;
        }

        if( 0 == ret )
        {
            to_len_or_ptr( *lpLenOrPtr, lpLenOrPtr );
            to_c_type( nType, &nType );
        }

        if( 0 == ret )
        {
            SQLRETURN r = SQLBindCol( m_hStmt, nCol + 1, nType, pBufByte, nBufSize, lpLenOrPtr );
            ret = m_err.stmt_ret( m_hStmt, r );
        }

        return ret;
    }

    // 
    // 绑定输出参数
    // 
    int odbc_stmt::bind_colum( int nCol, char * lpData, int nBufSize, xos::xos_int * StrLen_or_IndPtr )
    {
        int ret = 0;
        ret = bind_colum( nCol, VT_CHAR_ARRAY, lpData, nBufSize, StrLen_or_IndPtr );
        return ret;
    }

    // 
    // 绑定输出参数
    // 
    int odbc_stmt::bind_colum( int nCol, xos::xos_i64 * lpData, xos::xos_int * StrLen_or_IndPtr )
    {
        int ret = 0;
        ret = bind_colum( nCol, VT_I64, lpData, sizeof( xos::xos_i64 ), StrLen_or_IndPtr );
        return ret;
    }

    // 
    // 绑定输出参数
    // 
    int odbc_stmt::bind_colum( int nCol, xos::xos_i32 * lpData, xos::xos_int * StrLen_or_IndPtr )
    {
        int ret = 0;
        ret = bind_colum( nCol, VT_I32, lpData, sizeof( xos::xos_i32 ), StrLen_or_IndPtr );
        return ret;
    }

    // 
    // 绑定输出参数
    // 
    int odbc_stmt::bind_colum( int nCol, xos::xos_i16 * lpData, xos::xos_int * StrLen_or_IndPtr )
    {
        int ret = 0;
        ret = bind_colum( nCol, VT_I16, lpData, sizeof( xos::xos_i16 ), StrLen_or_IndPtr );
        return ret;
    }

    // 
    // 绑定输出参数
    // 
    int odbc_stmt::bind_colum( int nCol, xos::xos_i8 * lpData, xos::xos_int * StrLen_or_IndPtr )
    {
        int ret = 0;
        ret = bind_colum( nCol, VT_I8, lpData, sizeof( xos::xos_i8 ), StrLen_or_IndPtr );
        return ret;
    }

    // 
    // 绑定输出参数
    // 
    int odbc_stmt::bind_colum( int nCol, xos::xos_u64 * lpData, xos::xos_int * StrLen_or_IndPtr )
    {
        int ret = 0;
        ret = bind_colum( nCol, VT_U64, lpData, sizeof( xos::xos_u64 ), StrLen_or_IndPtr );
        return ret;
    }

    // 
    // 绑定输出参数
    // 
    int odbc_stmt::bind_colum( int nCol, xos::xos_u32 * lpData, xos::xos_int * StrLen_or_IndPtr )
    {
        int ret = 0;
        ret = bind_colum( nCol, VT_U32, lpData, sizeof( xos::xos_u32 ), StrLen_or_IndPtr );
        return ret;
    }

    // 
    // 绑定输出参数
    // 
    int odbc_stmt::bind_colum( int nCol, xos::xos_u16 * lpData, xos::xos_int * StrLen_or_IndPtr )
    {
        int ret = 0;
        ret = bind_colum( nCol, VT_U16, lpData, sizeof( xos::xos_u16 ), StrLen_or_IndPtr );
        return ret;
    }

    // 
    // 绑定输出参数
    // 
    int odbc_stmt::bind_colum( int nCol, xos::xos_u8 * lpData, xos::xos_int * StrLen_or_IndPtr )
    {
        int ret = 0;
        ret = bind_colum( nCol, VT_U8, lpData, sizeof( xos::xos_u8 ), StrLen_or_IndPtr );
        return ret;
    }

    // 
    // 绑定输出参数
    // 
    int odbc_stmt::bind_colum( int nCol, bool * lpData, xos::xos_int * StrLen_or_IndPtr )
    {
        int ret = 0;
        ret = bind_colum( nCol, VT_BOOL, lpData, sizeof( bool ), StrLen_or_IndPtr );
        return ret;
    }

    // 
    // 绑定输出参数
    // 
    int odbc_stmt::bind_colum( int nCol, float * lpData, xos::xos_int * StrLen_or_IndPtr )
    {
        int ret = 0;
        ret = bind_colum( nCol, VT_FLOAT, lpData, sizeof( float ), StrLen_or_IndPtr );
        return ret;
    }

    // 
    // 绑定输出参数
    // 
    int odbc_stmt::bind_colum( int nCol, double * lpData, xos::xos_int * StrLen_or_IndPtr )
    {
        int ret = 0;
        ret = bind_colum( nCol, VT_DOUBLE, lpData, sizeof( double ), StrLen_or_IndPtr );
        return ret;
    }

    // 
    // 设置是否异步执行sql
    // 
    int odbc_stmt::set_async( bool bAsync )
    {
        int ret = 0;

        if( 0 == ret )
        {
            SQLRETURN sqlRet = SQL_SUCCESS;
            if( bAsync )
            {
                sqlRet = SQLSetStmtAttr( m_hStmt, SQL_ATTR_ASYNC_ENABLE, ( SQLPOINTER )SQL_ASYNC_ENABLE_ON, SQL_IS_INTEGER );
            }
            else
            {
                sqlRet = SQLSetStmtAttr( m_hStmt, SQL_ATTR_ASYNC_ENABLE, ( SQLPOINTER )SQL_ASYNC_ENABLE_OFF, SQL_IS_INTEGER );
            }
            ret = m_err.stmt_ret( m_hStmt, sqlRet );
            LOG4( "set stmt async = %d, info = %s", bAsync, m_err.get_info( 0, 0, 0, 0 ) );
        }

        m_bAsync = bAsync;

        return ret;
    }

    // 
    // 下一结果集
    // 
    int odbc_stmt::next_results()
    {
        int ret = 0;

        if( ( 0 == ret ) && ( SQL_NULL_HSTMT == m_hStmt ) )
        {
            ret = 1;
        }

        if( 0 == ret )
        {
            SQLMoreResults( m_hStmt );
        }

        return ret;
    }

    // 
    //  0 : success
    //  1 : pending
    //  2 : no data
    // -1 : failed
    // 
    int odbc_stmt::fetch()
    {
        int ret = 0;

        if( ( 0 == ret ) && ( SQL_NULL_HSTMT == m_hStmt ) )
        {
            ret = -1;
        }

        if( 0 == ret )
        {
            SQLRETURN sqlRet = SQLFetch( m_hStmt );
            ret = m_err.stmt_ret( m_hStmt, sqlRet );
        }

        return ret;
    }

    // 
    // 执行DML后，影响的行数
    // 
    int odbc_stmt::get_affect_row_num( long long * lpnNum )
    {
        int ret = 0;

        SQLLEN nNum = 0;

        if( ( 0 == ret ) && ( SQL_NULL_HSTMT == m_hStmt ) )
        {
            ret = 1;
        }

        if( 0 == ret )
        {
            SQLRETURN r = SQLRowCount( m_hStmt, &nNum );
            if( SQL_SUCCESS != r )
            {
                m_err.get_info( SQL_HANDLE_STMT, m_hStmt );
                ret = 1;
            }
        }

        if( ( 0 == ret ) && lpnNum )
        {
            *lpnNum = nNum;
        }

        return ret;
    }

    // 
    // 得到结果集行数
    // 
    int odbc_stmt::get_result_row_num( long long * lpnNum )
    {
        int ret = 0;

        SQLLEN nRowNum = 0;

        if( ( 0 == ret ) && ( SQL_NULL_HSTMT == m_hStmt ) )
        {
            ret = 1;
        }

        if( 0 == ret )
        {
            SQLRETURN r = SQLFetchScroll( m_hStmt, SQL_FETCH_LAST, 0 );
            if( SQL_SUCCESS != r )
            {
                m_err.get_info( SQL_HANDLE_STMT, m_hStmt );
                ret = 1;
            }
        }

        if( 0 == ret )
        {
            SQLINTEGER nRetLen = 0;
            SQLRETURN r = SQLGetStmtAttrA( m_hStmt, SQL_ATTR_ROW_NUMBER, ( SQLPOINTER )&nRowNum, SQL_IS_INTEGER, &nRetLen );
            if( SQL_SUCCESS != r )
            {
                m_err.get_info( SQL_HANDLE_STMT, m_hStmt );
                ret = 1;
            }
        }

        if( ( 0 == ret ) && lpnNum )
        {
            *lpnNum = nRowNum;
        }

        return ret;
    }

    // 
    // 查询结果集中的列数
    // 
    int odbc_stmt::get_result_col_num( int * lpnNum )
    {
        int ret = 0;

        SQLSMALLINT nNum = 0;

        if( ( 0 == ret ) && ( SQL_NULL_HSTMT == m_hStmt ) )
        {
            ret = 1;
        }

        if( 0 == ret )
        {
            SQLRETURN r = SQLNumResultCols( m_hStmt, &nNum );
            if( SQL_SUCCESS != r )
            {
                m_err.get_info( SQL_HANDLE_STMT, m_hStmt );
                ret = 1;
            }
        }

        if( ( 0 == ret ) && lpnNum )
        {
            *lpnNum = nNum;
        }

        return ret;
    }

    // 
    // 查询结果集中的列数,index从0开始
    // 
    int odbc_stmt::get_col_name( int nIndex, char * lpszName, int nLen )
    {
        int ret = 0;

        SQLCHAR * lpuszName = ( SQLCHAR * )lpszName;
        SQLSMALLINT nLenNeed = 0;
        SQLSMALLINT data_type = 0;
        SQLULEN col_size = 0;
        SQLSMALLINT digit_num = 0;
        SQLSMALLINT can_null = 0;

        if( ( 0 == ret ) && ( SQL_NULL_HSTMT == m_hStmt ) )
        {
            ret = 1;
        }

        if( 0 == ret )
        {
            SQLRETURN r = SQLDescribeColA( m_hStmt, nIndex + 1, lpuszName, nLen, &nLenNeed, &data_type, &col_size, &digit_num, &can_null );
            if( SQL_SUCCESS != r )
            {
                m_err.get_info( SQL_HANDLE_STMT, m_hStmt );
                ret = 1;
            }
        }

        return ret;
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    int odbc_stmt::from_len_or_ptr( SQLLEN LenOrPtr, SQLLEN * lpLenOrPtr )
    {
        SQLLEN result = LenOrPtr;
        bool bTranslate = true;
        int ret = 0;

        switch( LenOrPtr )
        {
        case SQL_DEFAULT_PARAM:
            {
                result = LP_DEFAULT_PARAM;
            }
            break;
        case SQL_DATA_AT_EXEC:
            {
                result = LP_DATA_AT_EXEC;
            }
            break;
        case SQL_NULL_DATA:
            {
                result = LP_NULL_DATA;
            }
            break;
        case SQL_NTS:
            {
                result = LP_NTS;
            }
            break;
        default:
            {
                bTranslate = false;
            }
            break;
        }

        if( ( 0 == ret ) && bTranslate && lpLenOrPtr )
        {
            *lpLenOrPtr = result;
        }

        return ret;
    }

    int odbc_stmt::to_len_or_ptr( SQLLEN LenOrPtr, SQLLEN * lpLenOrPtr )
    {
        SQLLEN result = LenOrPtr;
        bool bTranslate = true;
        int ret = 0;

        switch( LenOrPtr )
        {
        case LP_DEFAULT_PARAM:
            {
                result = SQL_DEFAULT_PARAM;
            }
            break;
        case LP_DATA_AT_EXEC:
            {
                result = SQL_DATA_AT_EXEC;
            }
            break;
        case LP_NULL_DATA:
            {
                result = SQL_NULL_DATA;
            }
            break;
        case LP_NTS:
            {
                result = SQL_NTS;
            }
            break;
        default:
            {
                bTranslate = false;
            }
            break;
        }

        if( ( 0 == ret ) && bTranslate && lpLenOrPtr )
        {
            *lpLenOrPtr = result;
        }

        return ret;
    }

    int odbc_stmt::to_sql_io_type( int nInputType, int * lpnOutType )
    {
        int result = 0;
        int ret = 0;

        switch( nInputType )
        {
        case DIRECT_INPUT_OUTPUT:
            {
                result = SQL_PARAM_INPUT_OUTPUT;
            }
            break;
        case DIRECT_OUTPUT:
            {
                result = SQL_PARAM_OUTPUT;
            }
            break;
        case DIRECT_INPUT:
            {
                result = SQL_PARAM_INPUT;
            }
            break;
        default:
            {
                ret = 1;
            }
            break;
        }

        if( ( 0 == ret ) && lpnOutType )
        {
            *lpnOutType = result;
        }

        return ret;
    }

    int odbc_stmt::to_c_type( int nInputType, int * lpnOutType )
    {
        int result = 0;
        int ret = 0;

        switch( nInputType )
        {
        case VT_U16:
            {
                result = SQL_C_USHORT;
            }
            break;
        case VT_I16:
            {
                result = SQL_C_SSHORT;
            }
            break;
        case VT_U32:
            {
                result = SQL_C_ULONG;
            }
            break;
        case VT_I32:
            {
                result = SQL_C_SLONG;
            }
            break;
        case VT_U64:
            {
                result = SQL_C_UBIGINT;
            }
            break;
        case VT_I64:
            {
                result = SQL_C_SBIGINT;
            }
            break;
        case VT_FLOAT:
            {
                result = SQL_C_FLOAT;
            }
            break;
        case VT_DOUBLE:
            {
                result = SQL_C_DOUBLE;
            }
            break;
        case VT_CHAR_ARRAY:
            {
                result = SQL_C_CHAR;
            }
            break;
        case VT_I8:
            {
                result = SQL_C_STINYINT;
            }
            break;
        case VT_U8:
            {
                result = SQL_C_TINYINT;
            }
            break;
        case VT_BOOL:
            {
                result = SQL_C_BIT;
            }
            break;
        case VT_BIN:
            {
                result = SQL_C_BINARY;
            }
            break;
        default:
            {
                ret = 1;
            }
            break;
        }

        if( ( 0 == ret ) && lpnOutType )
        {
            *lpnOutType = result;
        }

        return ret;
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    int odbc_stmt::set_handle( SQLHANDLE hStmt )
    {
        int ret = 0;
        m_hStmt = hStmt;
        return ret;
    }

    SQLHANDLE odbc_stmt::handle()
    {
        return m_hStmt;
    }

    int odbc_stmt::init()
    {
        int ret = 0;
        return ret;
    }

    int odbc_stmt::term()
    {
        int ret = 0;

        if( SQL_NULL_HSTMT != m_hStmt )
        {
            SQLCloseCursor( m_hStmt );
            SQLFreeHandle( SQL_HANDLE_STMT, m_hStmt );
            m_hStmt = SQL_NULL_HSTMT;
        }

        init_data();

        return ret;
    }

    int odbc_stmt::init_data()
    {
        int ret = 0;
        m_hStmt = SQL_NULL_HSTMT;
        m_bAsync = false;
        m_sql = "";
        m_err.clear();
        return ret;
    }

} // xos_odbc
